//
//  ADCollectionViewModel.m
//  ADKit
//
//  Created by duzexu on 2018/4/4.
//

#import "ADCollectionViewModel.h"

@interface ADCollectionViewModel ()
@property (nonatomic, readwrite, strong) RACCommand *requestLocalDataCommand;
@property (nonatomic, readwrite, strong) RACCommand *requestRemoteDataCommand;
@property (nonatomic, readwrite, strong) RACSignal *requestDataSignal;
@property (nonatomic, readwrite, strong) RACSubject *reloadIndexPaths;

@property (nonatomic, assign) NSUInteger requestPage;
@property (nonatomic, assign) NSUInteger lastPage;

@end

@implementation ADCollectionViewModel

- (void)initialize {
    [super initialize];
    
    _dataSource = [NSMutableArray array];
    self.viewControllerClass = ADCollectionViewController.class;
    self.collectionViewLayout = [UICollectionViewFlowLayout new];
    self.itemSize = CGSizeMake(40, 40);
    self.contentInset = UIEdgeInsetsMake(AD_APPLICATION_TOP_BAR_HEIGHT, 0, AD_SAFEAREAINSETS_PORTRAIT.bottom, 0);
    self.page = 1;
    self.noMoreData = YES;
    
    @weakify(self)
    /// request local data
    self.requestLocalDataCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
        @strongify(self)
        return [self fetchLocalData];
    }];
    /// request remote data
    self.requestRemoteDataCommand = [[RACCommand alloc] initWithSignalBlock:^(NSNumber *page) {
        @strongify(self)
        self.requestPage = page.unsignedIntegerValue;
        return [[self requestRemoteDataSignalWithPage:page.unsignedIntegerValue] takeUntil:self.rac_willDeallocSignal];
    }];
    
    [self.requestLocalDataCommand.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {
        @strongify(self)
        [self localDataProcess:x];
    }];
    
    if (self.shouldFetchLocalDataOnViewModelInitialize) {
        RACSignal *fetchLocalDataSignal = self.requestLocalDataCommand.executionSignals.switchToLatest;
        RACSignal *requestRemoteDataSignal = self.requestRemoteDataCommand.executionSignals.switchToLatest;
        self.requestDataSignal = [[fetchLocalDataSignal merge:requestRemoteDataSignal] deliverOnMainThread];
    }else{
        self.requestDataSignal = [self.requestRemoteDataCommand.executionSignals.switchToLatest deliverOnMainThread];
    }
    
    [[self.requestRemoteDataCommand.executionSignals.switchToLatest map:[self requestDataMapper]] subscribeNext:^(id  _Nullable x) {
        @strongify(self)
        [self cacheWithRemoteData:x];
        [self remoteDataProcess:x];
        self.lastPage = self.requestPage;
    }];
    
    /// 过滤错误信息
    [[self.requestRemoteDataCommand.errors
      filter:[self requestRemoteDataErrorsFilter]]
     subscribe:self.errors];
    
    self.reloadIndexPaths = [RACSubject subject];
}

- (id (^)(id value))requestDataMapper {
    return ^(id value) {
        return value;
    };
}

- (void)localDataProcess:(id)x {
    if ([x isKindOfClass:NSArray.class]) {
        [self.dataSource removeAllObjects];
        [self.dataSource addObjectsFromArray:x];
        [self reloadDataSource];
    }
}

- (void)remoteDataProcess:(id)x {
    if ([x isKindOfClass:NSArray.class]) {
        if (self.requestPage == 1) {
            [self.dataSource removeAllObjects];
            [self.dataSource addObjectsFromArray:x];
        }else if (self.requestPage > self.lastPage){
            [self.dataSource addObjectsFromArray:x];
        }
        [self reloadDataSource];
    }
}

- (void)requestDataCompleted {}

- (UICollectionView *)collectionView {
    return ((ADCollectionViewController *)self.viewController).collectionView;
}

/// sub class can ovrride it
- (BOOL (^)(NSError *error))requestRemoteDataErrorsFilter {
    return ^(NSError *error) {
        return YES;
    };
}

- (RACSignal *)fetchLocalData {
    NSData *cacheData = [self cacheData];
    if (cacheData) {
        return [RACSignal return:cacheData];
    }
    return [RACSignal empty];
}

- (RACSignal *)requestRemoteDataSignalWithPage:(NSUInteger)page {
    return [RACSignal empty];
}

- (void)reloadDataSource {
    [_reloadIndexPaths sendNext:nil];
}

- (void)reloadDataSourceWithIndexPath:(NSIndexPath *)indexPath {
    [_reloadIndexPaths sendNext:indexPath];
}

- (void)reloadDataSourceWithIndexPaths:(NSArray *)indexPaths {
    [_reloadIndexPaths sendNext:indexPaths];
}

#pragma mark - Cache
- (id)cacheData {
    return [NSKeyedUnarchiver unarchiveObjectWithData:[NSData dataWithContentsOfFile:[self cachePath]]];
}

- (void)cacheWithRemoteData:(id)x {
    if (self.shouldCacheData && self.requestPage == 1) {
        if ([x isKindOfClass:RACTuple.class]) {
            RACTuple *tuple = (RACTuple *)x;
            [NSKeyedArchiver archiveRootObject:tuple.allObjects toFile:[self cachePath]];
        }else {
            [NSKeyedArchiver archiveRootObject:x toFile:[self cachePath]];
        }
    }
}

#pragma mark - overrite
- (void)registCollectionViewCell:(UICollectionView *)collectionView {
    [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"UICollectionViewCell"];
}

- (NSString *)collectionView:(UICollectionView *)collectionView cellIdentifierForIndexPath:(NSIndexPath *)indexPath withObject:(id)object {
    return @"UICollectionViewCell";
}

- (void)configureCell:(UICollectionViewCell *)cell atIndexPath:(NSIndexPath *)indexPath withObject:(id)object {}

#pragma mark - UICollectionDelegate & Datasource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    if (self.shouldMultiSections) return self.dataSource ? self.dataSource.count : 0;
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    if (self.shouldMultiSections) return [self.dataSource[section] count];
    return self.dataSource.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    // fetch object
    id object = nil;
    if (self.shouldMultiSections) object = self.dataSource[indexPath.section][indexPath.row];
    if (!self.shouldMultiSections) object = self.dataSource[indexPath.row];
    
    NSString *cellIdentifier = [self collectionView:collectionView cellIdentifierForIndexPath:indexPath withObject:object];
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    /// bind model
    [self configureCell:cell atIndexPath:indexPath withObject:(id)object];
    return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return self.itemSize;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    // execute commond
    [self.didSelectCommand execute:indexPath];
}

@end
